/* ----------------------------------------------------------------------------
* File: api_proxy.cpp
*
* Desc: Proxy to Skype API
*
* Created: 03/05/2011, by Alexey Korshunov
* ---------------------------------------------------------------------------- */
#include <tchar.h>
#include <windows.h>

#include "api_proxy.h"
#include "debug_logger.h"		

namespace SkypeProtection
{
	APIProxy::APIProxy(bool registerAPI) 
		throw(Common::Exception)
		: registerAPI(registerAPI)
		, m_StartEvent(NULL)
	{
		m_Logger = Common::CreateDebugLogger();
		if (!m_Logger.get())
			throw Common::Exception("SkypeProxy: ERROR - Unable to create debug logger");

		m_StartEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
		if (m_StartEvent == NULL)
		{
			m_Logger->Print("SkypeProxy: ERROR - Unable to create start event");
			throw Common::Exception("SkypeProxy: ERROR - Unable to create start event");
		}
	}

	APIProxy::~APIProxy()
	{
		StopThread();
		::CloseHandle(m_StartEvent);
	}

	Common::Error APIProxy::Start()
	{
		if (!StartThread())
			return Common::SKYPE_ERROR;

		WaitForSingleObject(m_StartEvent, INFINITE);
		::ResetEvent(m_StartEvent);
		return Common::SKYPE_SUCCESS;
	}

	Common::Error APIProxy::Stop()
	{
		StopThread();
		return Common::SKYPE_SUCCESS;
	}

	Common::Error APIProxy::Run()
	{
		Common::Error err = Common::SKYPE_SUCCESS;
		SKYPE4COMLib::ISkypePtr skype = CreateCOMInstance();
		::SetEvent(m_StartEvent);

		try
		{
			if ((err = RunLogic(skype.GetInterfacePtr())) != Common::SKYPE_SUCCESS)
				m_Logger->Print("SkypeProxy: ERROR - Error while run");
		}
		catch(const Common::Exception& ex)
		{
			m_Logger->Print("SkypeProxy: EXCEPTION - %s", ex.GetStr().c_str());
			err = Common::SKYPE_ERROR;
		}
		catch(...)
		{
			m_Logger->Print("SkypeProxy: ERROR - Undefined exception");
			err = Common::SKYPE_ERROR;
		}

		skype = NULL;
		CoUninitialize();
		return err;
	}

	bool APIProxy::IsExistFile(const char* FileName)
	{
		return ::GetFileAttributesA(FileName) != DWORD(-1);
	}

	void APIProxy::RegisterAPILibrary()
	{
		char AppPath[MAX_PATH] = "";
		char AppDirectory[MAX_PATH] = "";
		char LibraryPath[MAX_PATH] = "";
		char DllName[] = {'S','k','y','p','e','4','C','O','M','.','d','l','l','\0'};

		if (::GetModuleFileNameA(NULL, AppPath, MAX_PATH) == 0)
			throw Common::Exception("SkypeProxy: ERROR - Unable to get module file name");

		strncpy(AppDirectory, AppPath, strrchr(AppPath, '\\') + 1 - AppPath);
		AppDirectory[strlen(AppDirectory)] = '\0';

		strncpy(LibraryPath, AppDirectory, strlen(AppDirectory));
		strncat(LibraryPath, DllName, strlen(DllName) + 1);

		m_Logger->Print("SkypeProxy: LibraryPath - %s", LibraryPath);

		// Existing
		if (!IsExistFile(LibraryPath))
			throw Common::Exception("SkypeProxy: ERROR - Unable to find Skype API library");
		m_Logger->Print("SkypeProxy: Skype API library is found");

		// Register API library
		HINSTANCE hinst;
		hinst = ::ShellExecuteA(NULL, "open", "regsvr32", DllName, NULL, SW_HIDE);
		if ((int)hinst <= 32)
			throw Common::Exception("SkypeProxy: ERROR - Unable to register Skype4COM.dll");
		m_Logger->Print("SkypeProxy: Skype4COM.dll - registering (OK)");
	}

	SKYPE4COMLib::ISkypePtr APIProxy::CreateCOMInstance()
	{
		// Library registering
		if (registerAPI)
			RegisterAPILibrary();
			
		// Create instance	
		CoInitialize(NULL);
		SKYPE4COMLib::ISkypePtr skype;
		HRESULT hr = skype.CreateInstance(__uuidof(SKYPE4COMLib::Skype));
		if (hr != S_OK)
		{
			CoUninitialize();
			m_Logger->Print("SkypeProxy: ERROR - Unable to create COM instance, error = 0x%08x", hr);
			throw Common::Exception("SkypeProxy: ERROR - Unable to create COM instance");
		} 
		return skype;
	}
}